﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using MxDrawXLib;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using CommandLine;

namespace Dwg2Json
{
    public static class Program
    {
        public static string DEFAULT_XDATA_APPNAME = "VENTANALY_APPNAME";
        public static string CUSTOM_ENTITY_FIELDS_DICT_KEY = "VENTANALY_FIELDS_DICT_KEY";
        public static string ERROR_FILE = "Dwg2Json.err";
        public static int ENTITY_CHUNK_SIZE = 10000; // 图元分块(分批次发送,减轻服务器压力)
        public static bool ENABLE_GZIP_COMPRESSION = false; // 启动gzip压缩
        public static HashSet<string> EMPTY_BLOCK_HASH_SET = new HashSet<string>();

        public static JObject CadColorToJson(MxDrawMcCmColor color)
        {
            JObject obj = new JObject();
            obj["ColorIndex"] = color.colorIndex;
            obj["ColorMethod"] = (int)color.ColorMethod;
            obj["EntityColor"] = color.EntityColor;
            return obj;
        }

        public static JObject CadPointToJson(MxDrawPoint pt)
        {
            JObject obj = new JObject();
            obj["x"] = pt.x;
            obj["y"] = pt.y;
            obj["z"] = pt.z;
            return obj;
        }

        public static JObject CadVectorToJson(MxDrawVector3d v)
        {
            JObject obj = new JObject();
            obj["x"] = v.x;
            obj["y"] = v.y;
            obj["z"] = v.z;
            return obj;
        }

        public static JObject CadScale3dToJson(MxDrawScale3d v)
        {
            JObject obj = new JObject();
            obj["sx"] = v.sx;
            obj["sy"] = v.sy;
            obj["sz"] = v.sz;
            return obj;
        }

        public static string GetClassName(MxDrawEntity ent)
        {
            if (ent == null) return "";
            // 根据ObjectName(C++类名称)进行判断
            if (ent.ObjectName == "MxDrawXCustomEntity")
            {
                MxDrawCustomEntity customEnt = (MxDrawCustomEntity)ent;
                // 自定义图元,Guid即是它的类型
                return customEnt.Guid;
            }
            else
            {
                // 内置图元
                return ent.ObjectName;
            }
        }

        public static JObject GetEntityParams(MxDrawEntity ent)
        {
            JObject obj = new JObject();
            string sType = ent.ObjectName;
            //sType = sType.Replace("McDb", "");
            if (sType == "McDbLine")
            {
                MxDrawLine line = (MxDrawLine)ent;
                obj["StartPoint"] = CadPointToJson(line.StartPoint);
                obj["EndPoint"] = CadPointToJson(line.EndPoint);
            }
            else if (sType == "McDbCircle")
            {
                MxDrawCircle circle = (MxDrawCircle)ent;
                obj["Center"] = CadPointToJson(circle.Center);
                obj["Radius"] = circle.Radius;
            }
            else if (sType == "McDbArc")
            {
                MxDrawArc arc = (MxDrawArc)ent;
                obj["Center"] = CadPointToJson(arc.Center);
                obj["Radius"] = arc.Radius;
                obj["StartAngle"] = arc.StartAngle;
                obj["EndAngle"] = arc.EndAngle;
            }
            else if (sType == "McDbEllipse")
            {
                MxDrawEllipse ellipse = (MxDrawEllipse)ent;
                obj["Center"] = CadPointToJson(ellipse.Center);
                obj["MajorAxis"] = CadVectorToJson(ellipse.MajorAxis);
                obj["MinorAxis"] = CadVectorToJson(ellipse.MinorAxis);
                obj["StartAngle"] = ellipse.StartAngle;
                obj["EndAngle"] = ellipse.EndAngle;
                obj["RadiusRatio"] = ellipse.RadiusRatio;
            }
            else if (sType == "McDbPolyline")
            {
                MxDrawPolyline polyline = (MxDrawPolyline)ent;
                obj["NumVerts"] = polyline.NumVerts;
                obj["ConstantWidth"] = polyline.ConstantWidth;
                obj["IsClosedStatus"] = polyline.IsClosedStatus;
                obj["Elevation"] = polyline.Elevation;
            }
            else if (sType == "McDbRay")
            {
                MxDrawRay ray = (MxDrawRay)ent;
                obj["BasePoint"] = CadPointToJson(ray.basePoint);
                obj["UnitDir"] = CadVectorToJson(ray.UnitDir);
            }
            else if (sType == "McDbXline")
            {
                MxDrawXline xline = (MxDrawXline)ent;
                obj["BasePoint"] = CadPointToJson(xline.basePoint);
                obj["UnitDir"] = CadVectorToJson(xline.UnitDir);
            }
            else if (sType == "McDbMline")
            {
                // 注: 该类目前不存在
                return null;
            }
            else if (sType == "McDbHatch")
            {
                MxDrawHatch hatch = (MxDrawHatch)ent;
                obj["Elevation"] = hatch.Elevation;
                obj["GradientAngle"] = hatch.GradientAngle;
                obj["GradientName"] = hatch.GradientName;
                obj["GradientOneColorMode"] = hatch.GradientOneColorMode;
                obj["GradientType"] = (int)hatch.GradientType;
                obj["HatchObjectType"] = (int)hatch.HatchObjectType;
                obj["HatchStyle"] = (int)hatch.HatchStyle;
                //obj["NumLoops"] = hatch.NumLoops;
                obj["PatternAngle"] = hatch.PatternAngle;
                obj["PatternDouble"] = hatch.PatternDouble;
                obj["PatternName"] = hatch.PatternName;
                obj["PatternScale"] = hatch.PatternScale;
                obj["PatternSpace"] = hatch.PatternSpace;
                obj["PatternType"] = (int)hatch.PatternType;
                obj["ShadeTintValue"] = hatch.ShadeTintValue;
            }
            else if (sType == "McDbMText")
            {
                MxDrawMText mtext = (MxDrawMText)ent;
                if (mtext.Contents == "")
                {
                    return null;
                }
                obj["Location"] = CadPointToJson(mtext.Location);
                obj["Contents"] = mtext.Contents;
                obj["Rotation"] = mtext.Rotation;
                obj["TextHeight"] = mtext.TextHeight;
                obj["Width"] = mtext.Width;
                obj["Attachment"] = (int)mtext.Attachment;
                obj["Direction"] = CadVectorToJson(mtext.Direction);
            }
            else if (sType == "McDbText")
            {
                MxDrawText text = (MxDrawText)ent;
                if (text.TextString == "")
                {
                    return null;
                }
                obj["Position"] = CadPointToJson(text.Position);
                obj["TextString"] = text.TextString;
                obj["Rotation"] = text.Rotation;
                obj["Height"] = text.Height;
                obj["WidthFactor"] = text.WidthFactor;
                obj["AlignmentPoint"] = CadPointToJson(text.AlignmentPoint);
                obj["HorizontalMode"] = (int)text.horizontalMode;
                obj["verticalMode"] = (int)text.verticalMode;
                obj["Oblique"] = text.Oblique;
            }
            else if (sType == "McDbPoint")
            {
                MxDrawPointEntity point = (MxDrawPointEntity)ent;
                obj["Position"] = CadPointToJson(point.Position);
            }
            else if (sType == "McDbProxyEntity")
            {
                MxDrawProxyEntity proxyEnt = (MxDrawProxyEntity)ent;
                obj["originalClassName"] = proxyEnt.originalClassName;
            }
            else if (sType == "McDbCustomEntity")
            {
                MxDrawCustomEntity customEnt = (MxDrawCustomEntity)ent;
                obj["Guid"] = customEnt.Guid;
            }
            else if (sType == "McDbRasterImage")
            {
                MxDrawRasterImage image = (MxDrawRasterImage)ent;
                obj["ImageDefId"] = image.ImageDefId;
            }
            else if (sType == "McDbSolid")
            {
                MxDrawSolid soild = (MxDrawSolid)ent;
            }
            else if (sType == "McDbSpline")
            {
                MxDrawSpline spline = (MxDrawSpline)ent;
            }
            else if (sType == "McDbTrace")
            {
                MxDrawTrace trace = (MxDrawTrace)ent;
            }
            else if (sType == "McDbWipeout")
            {
                // 该类目前不存在
                return null;
            }
            else if (sType == "McDbDimAligned")
            {
                // 对齐标注
                MxDrawDimAligned dim = (MxDrawDimAligned)ent;
                // 共有属性
                obj["DimensionStyle"] = dim.DimensionStyle;
                obj["DimensionText"] = dim.DimensionText;
                obj["Elevation"] = dim.Elevation;
                obj["HorizontalRotation"] = dim.HorizontalRotation;
                obj["TextAttachment"] = (int)dim.TextAttachment;
                obj["TextPosition"] = CadPointToJson(dim.TextPosition);
                obj["TextRotation"] = dim.TextRotation;
                obj["UsingDefaultTextPosition"] = dim.UsingDefaultTextPosition;
                // 特有属性
                obj["DimLinePoint"] = CadPointToJson(dim.DimLinePoint);
                obj["Oblique"] = dim.Oblique;
                obj["XLine1Point"] = CadPointToJson(dim.XLine1Point);
                obj["XLine2Point"] = CadPointToJson(dim.XLine2Point);
            }
            else if (sType == "McDbDimRadial")
            {
                // 半径标注
                MxDrawDimRadial dim = (MxDrawDimRadial)ent;
                // 共有属性
                obj["DimensionStyle"] = dim.DimensionStyle;
                obj["DimensionText"] = dim.DimensionText;
                obj["Elevation"] = dim.Elevation;
                obj["HorizontalRotation"] = dim.HorizontalRotation;
                obj["TextAttachment"] = (int)dim.TextAttachment;
                obj["TextPosition"] = CadPointToJson(dim.TextPosition);
                obj["TextRotation"] = dim.TextRotation;
                obj["UsingDefaultTextPosition"] = dim.UsingDefaultTextPosition;
                // 特有属性
                obj["Center"] = CadPointToJson(dim.Center);
                obj["ChordPoint"] = CadPointToJson(dim.ChordPoint);
                obj["ExtArcStartAngle"] = dim.ExtArcStartAngle;
                obj["ExtArcEndAngle"] = dim.ExtArcEndAngle;
                obj["LeaderLength"] = dim.LeaderLength;
            }
            else if (sType == "McDbDimDiametric")
            {
                // 直径标注
                MxDrawDimDiametric dim = (MxDrawDimDiametric)ent;
                // 共有属性
                obj["DimensionStyle"] = dim.DimensionStyle;
                obj["DimensionText"] = dim.DimensionText;
                obj["Elevation"] = dim.Elevation;
                obj["HorizontalRotation"] = dim.HorizontalRotation;
                obj["TextAttachment"] = (int)dim.TextAttachment;
                obj["TextPosition"] = CadPointToJson(dim.TextPosition);
                obj["TextRotation"] = dim.TextRotation;
                obj["UsingDefaultTextPosition"] = dim.UsingDefaultTextPosition;
                // 特有属性
                obj["ChordPoint"] = CadPointToJson(dim.ChordPoint);
                obj["FarChordPoint"] = CadPointToJson(dim.FarChordPoint);
                obj["LeaderLength"] = dim.LeaderLength;
            }
            else if (sType == "McDbDimRotated")
            {
                // 旋转标注
                MxDrawDimRotated dim = (MxDrawDimRotated)ent;
                // 共有属性
                obj["DimensionStyle"] = dim.DimensionStyle;
                obj["DimensionText"] = dim.DimensionText;
                obj["Elevation"] = dim.Elevation;
                obj["HorizontalRotation"] = dim.HorizontalRotation;
                obj["TextAttachment"] = (int)dim.TextAttachment;
                obj["TextPosition"] = CadPointToJson(dim.TextPosition);
                obj["TextRotation"] = dim.TextRotation;
                obj["UsingDefaultTextPosition"] = dim.UsingDefaultTextPosition;
                // 特有属性
                obj["DimLinePoint"] = CadPointToJson(dim.DimLinePoint);
                obj["Oblique"] = dim.Oblique;
                obj["Rotation"] = dim.Rotation;
                obj["XLine1Point"] = CadPointToJson(dim.XLine1Point);
                obj["XLine2Point"] = CadPointToJson(dim.XLine2Point);
            }
            else if (sType == "McDbDimAngular")
            {
                // 二维角度标注
                MxDrawDimAngular dim = (MxDrawDimAngular)ent;
                // 共有属性
                obj["DimensionStyle"] = dim.DimensionStyle;
                obj["DimensionText"] = dim.DimensionText;
                obj["Elevation"] = dim.Elevation;
                obj["HorizontalRotation"] = dim.HorizontalRotation;
                obj["TextAttachment"] = (int)dim.TextAttachment;
                obj["TextPosition"] = CadPointToJson(dim.TextPosition);
                obj["TextRotation"] = dim.TextRotation;
                obj["UsingDefaultTextPosition"] = dim.UsingDefaultTextPosition;
                // 特有属性
                obj["ArcPoint"] = CadPointToJson(dim.ArcPoint);
                obj["XLine1Start"] = CadPointToJson(dim.XLine1Start);
                obj["XLine1End"] = CadPointToJson(dim.XLine1End);
                obj["XLine2Start"] = CadPointToJson(dim.XLine2Start);
                obj["XLine2End"] = CadPointToJson(dim.XLine2End);
            }
            else if (sType == "McDbAttributeDefinition")
            {
                MxDrawAttributeDefinition attrDef = (MxDrawAttributeDefinition)ent;
                // MxDrawText公共属性
                obj["Position"] = CadPointToJson(attrDef.Position);
                obj["TextString"] = attrDef.TextString;
                obj["Rotation"] = attrDef.Rotation;
                obj["Height"] = attrDef.Height;
                obj["WidthFactor"] = attrDef.WidthFactor;
                obj["AlignmentPoint"] = CadPointToJson(attrDef.AlignmentPoint);
                obj["HorizontalMode"] = (int)attrDef.horizontalMode;
                obj["verticalMode"] = (int)attrDef.verticalMode;
                obj["Oblique"] = attrDef.Oblique;
                // MxDrawAttributeDefinition特有属性
                obj["IsConstant"] = attrDef.IsConstant;
                obj["IsInvisible"] = attrDef.IsInvisible;
                obj["Tag"] = attrDef.Tag;
                obj["Prompt"] = attrDef.Prompt;
            }
            else if (sType == "McDbAttribute")
            {
                MxDrawAttribute attrib = (MxDrawAttribute)ent;
                // MxDrawText公共属性
                obj["Position"] = CadPointToJson(attrib.Position);
                obj["TextString"] = attrib.TextString;
                obj["Rotation"] = attrib.Rotation;
                obj["Height"] = attrib.Height;
                obj["WidthFactor"] = attrib.WidthFactor;
                obj["AlignmentPoint"] = CadPointToJson(attrib.AlignmentPoint);
                obj["HorizontalMode"] = (int)attrib.horizontalMode;
                obj["verticalMode"] = (int)attrib.verticalMode;
                obj["Oblique"] = attrib.Oblique;
                // MxDrawAttribute特有属性
                obj["IsConstant"] = attrib.IsConstant;
                obj["IsInvisible"] = attrib.IsInvisible;
                obj["Tag"] = attrib.Tag;
            }
            else if (sType == "McDbBlockReference")
            {
                MxDrawBlockReference blkRef = (MxDrawBlockReference)ent;
                if (EMPTY_BLOCK_HASH_SET.Contains(blkRef.GetBlockName()))
                {
                    // 剔除空块的块引用对象
                    return null;
                }
                obj["AttributeCount"] = blkRef.AttributeCount;
                obj["BlockTableRecordId"] = blkRef.BlockTableRecordId;
                obj["blockName"] = blkRef.GetBlockName();
                obj["Position"] = CadPointToJson(blkRef.Position);
                obj["Rotation"] = blkRef.Rotation;
            }
            else
            {
                // 其它图元, 后续再补充完善
            }
            return obj;
        }

        public static void HackGetEntityParams(MxDrawEntity ent, JObject obj)
        {
            // 根据id获取图元类型(c++类型名称)
            string sType = GetClassName(ent);
            // 特殊处理多段线
            if (sType == "McDbPolyline")
            {
                MxDrawPolyline polyline = (MxDrawPolyline)ent;
                List<double> startWidths = new List<double>();
                List<double> endWidths = new List<double>();
                List<double> bulges = new List<double>();
                List<JObject> points = new List<JObject>();
                for (int i = 0; i < polyline.NumVerts; i++)
                {
                    var pt = polyline.GetPointAt(i);
                    var bulge = polyline.GetBulgeAt(i);
                    var width1 = polyline.GetSWidthsAt(i);
                    var width2 = polyline.GetEWidthsAt(i);
                    startWidths.Add(width1);
                    endWidths.Add(width2);
                    bulges.Add(bulge);
                    points.Add(CadPointToJson(pt));
                }

                obj["startWidths"] = JArray.FromObject(startWidths);
                obj["endWidths"] = JArray.FromObject(endWidths);
                obj["bulges"] = JArray.FromObject(bulges);
                obj["points"] = JArray.FromObject(points);
            }
            else if (sType == "McDbHatch")
            {
                MxDrawHatch hatch = (MxDrawHatch)ent;
                // 读取hatch数据
                // https://www.mxdraw.com/help/index.htm
                JArray _loops = new JArray();
                for (int i = 0; i < hatch.NumLoops; i++)
                {
                    if (!hatch.LoopTypeIsPolyline(i))
                    {
                        // 暂不支持曲线类型的边界.
                        continue;
                    }
                    var iLootType = hatch.LoopTypeAt(i);
                    var loop = hatch.GetLoopAt(i);
                    if (loop == null) continue;
                    // 下面可以得每个点的坐标，凸度.

                    JArray points = new JArray();
                    JArray bulges = new JArray();
                    for (int j = 0; j + 1 < loop.Count; j += 2)
                    {
                        var pt = loop.AtPoint(j);
                        var dBulge = loop.AtDouble(j + 1);
                        points.Add(CadPointToJson(pt));
                        bulges.Add(dBulge);
                    }
                    JObject _loop = new JObject();
                    _loop["loopType"] = iLootType;
                    _loop["points"] = points;
                    _loop["bulges"] = bulges;
                    _loops.Add(_loop);
                }
                JArray _patterns = new JArray();
                // 读取图案定义数据
                for (int i = 0; i < hatch.NumPatternDefinitions(); i++)
                {
                    double angle = 0.0;
                    double baseX = 0.0;
                    double baseY = 0.0;
                    double offsetX = 0.0;
                    double offsetY = 0.0;
                    // TODO 待修复: 图案定义angle、baseX等无法返回(js无法进行引用或者指针传递)
                    MxDrawResbuf defData = hatch.GetPatternDefinitionAt(
                      i,
                      out angle,
                      out baseX,
                      out baseY,
                      out offsetX,
                      out offsetY
                    );
                    if (defData == null) continue;
                    // 下面可以得每个图案定义线型数据
                    JArray _dashes = new JArray();
                    for (int j = 0; j + 1 < defData.Count; j++)
                    {
                        var dDashe = defData.AtDouble(j);
                        _dashes.Add(dDashe);
                    }
                    JObject _pattern = new JObject();
                    _pattern["angle"] = angle;
                    _pattern["baseX"] = baseX;
                    _pattern["baseY"] = baseY;
                    _pattern["offsetX"] = offsetX;
                    _pattern["offsetY"] = offsetY;
                    _pattern["dashes"] = _dashes;
                    _patterns.Add(_pattern);
                }
                obj["loops"] = _loops;
                obj["patterns"] = _patterns;
            }
            else if (sType == "McDbBlockReference")
            {
                MxDrawBlockReference blkRef = (MxDrawBlockReference)ent;
                obj["blockName"] = blkRef.GetBlockName();
                // 替换缩放因子
                obj["ScaleFactors"] = CadScale3dToJson(blkRef.ScaleFactors);
                // 替换行列
                var matrix = blkRef.BlockTransform;
                double[,] _matrix = new double[4, 4];
                for (short i = 0; i < 4; i++)
                {
                    for (short j = 0; j < 4; j++)
                    {
                        _matrix[i, j] = matrix.Get(i, j);
                    }
                }
                obj["BlockTransform"] = JArray.FromObject(_matrix);
                // if (obj.hasOwnProperty("BlockTableRecordId")) {
                //   var blockTableRec = mxOcx.ObjectIdToObject(obj["BlockTableRecordId"])
                //   if (blockTableRec) {
                //     obj["blockName"] = blockTableRec.Name
                //   } else {
                //     obj["blockName"] = ""
                //   }
                // }
            }
            else if (sType == "McDbSpline")
            {
                MxDrawSpline spline = (MxDrawSpline)ent;
                var fitPoints = spline.GetFitPoints();
                // 拟合方式
                if (fitPoints.Count > 0)
                {
                    JArray _fitPoints = new JArray();
                    for (int i = 0; i < fitPoints.Count; i++)
                    {
                        MxDrawPoint pt = fitPoints.Item(i);
                        _fitPoints.Add(CadPointToJson(pt));
                    }
                    // 得到startTangent
                    MxDrawResbuf retT1 = spline.GetProp("startTangent");
                    JObject startTangent = new JObject();
                    startTangent["x"] = retT1.AtDouble(0);
                    startTangent["y"] = retT1.AtDouble(1);
                    startTangent["z"] = retT1.AtDouble(2);
                    // 得到endTangent
                    MxDrawResbuf retT2 = spline.GetProp("endTangent");
                    JObject endTangent = new JObject();
                    endTangent["x"] = retT2.AtDouble(0);
                    endTangent["y"] = retT2.AtDouble(1);
                    endTangent["z"] = retT2.AtDouble(2);

                    obj["fitPoints"] = _fitPoints;
                    obj["startTangent"] = startTangent;
                    obj["endTangent"] = endTangent;
                }
                else
                {
                    // 控制点方式
                    var ctrlPoints = spline.GetControlPoints();
                    JArray _ctrlPoints = new JArray();
                    for (int i = 0; i < ctrlPoints.Count; i++)
                    {
                        var pt = ctrlPoints.Item(i);
                        _ctrlPoints.Add(CadPointToJson(pt));
                    }
                    var weights = spline.GetWeights();
                    JArray _weights = new JArray();
                    for (int i = 0; i < weights.Count; i++)
                    {
                        _weights.Add(weights.AtDouble(i));
                    }
                    var knots = spline.GetKnots();
                    JArray _knots = new JArray();
                    for (int i = 0; i < knots.Count; i++)
                    {
                        _knots.Add(knots.AtDouble(i));
                    }
                    obj["ctrlPoints"] = _ctrlPoints;
                    obj["weights"] = _weights;
                    obj["knots"] = _knots;
                    // 是否闭合
                    obj["closed"] = spline.IsClosed();
                    // 是否周期
                    // 是否平面
                }
            }

            else if (sType == "McDbSolid")
            {
                MxDrawSolid solid = (MxDrawSolid)ent;
                JArray points = new JArray();
                for (int i = 0; i < 4; i++)
                {
                    var pt = solid.GetPointAt(i);
                    points.Add(CadPointToJson(pt));
                }
                obj["points"] = points;
            }
        }

        public static MxDrawDictionary GetExtDict(IMxDrawEntity ent)
        {
            MxDrawDictionary dict = ent.GetExtensionDictionary();
            if (dict == null)
            {
                ent.SetProp("createExtensionDictionary", new MxDrawResbuf());
                dict = ent.GetExtensionDictionary();
            }
            return dict;
        }

        public static JObject GET_DICT_KEY_VALUES(MxDrawDictionary dict)
        {
            JObject obj = new JObject();
            if (dict != null)
            {
                List<string> names = new List<string>();
                var iter = dict.NewIterator();
                // 汇总当前词典下的所有key
                for (; !iter.Done(); iter.Step())
                {
                    names.Add(iter.Name());
                }
                // 显式释放内存
                System.Runtime.InteropServices.Marshal.ReleaseComObject(iter);
                foreach (var name in names)
                {
                    var xRecord = (MxDrawXRecord)dict.GetAt(name);
                    if (xRecord == null) continue;
                    var ret = xRecord.GetXRecordData();
                    if (ret == null) continue;
                    obj[name] = ret.AtString(0);
                }
            }
            return obj;
        }


        public static JObject GET_DICT_XDATA(MxDrawDictionary dict)
        {
            JObject xdata = new JObject();
            var obj = GET_DICT_KEY_VALUES(dict);
            if (obj != null)
            {
                foreach (var item in obj)
                {
                    string key = item.Key;
                    // 忽略特殊的key
                    if (key == CUSTOM_ENTITY_FIELDS_DICT_KEY) continue;
                    string uKey = key.ToUpper();
                    JObject data = JObject.Parse(item.Value.ToObject<String>());
                    // 是否json字符串
                    if (data != null)
                    {
                        if (data.ContainsKey("field") && data.ContainsKey("value"))
                        {
                            JObject _obj = new JObject();
                            _obj["field"] = data["field"];
                            _obj["value"] = data["value"];
                            xdata[uKey] = _obj;
                        }
                        else
                        {
                            JObject _obj = new JObject();
                            _obj["field"] = key;
                            _obj["value"] = obj[key];
                            xdata[uKey] = _obj;
                        }
                    }
                    else
                    {
                        JObject _obj = new JObject();
                        _obj["field"] = key;
                        _obj["value"] = obj[key];
                        xdata[uKey] = _obj;
                    }
                }
            }
            return xdata;
        }

        public static List<object> GetEntityXData(IMxDrawEntity ent, string appName)
        {
            MxDrawResbuf ret = ent.GetXData(appName);
            if (ret == null) return null;

            List<object> obj = new List<object>();
            for (int i = 0; i < ret.Count; i++)
            {
                long dType = ret.ItemDataType(i);
                if (dType == (long)XDataCode.String)
                {
                    obj.Add(ret.AtString(i));
                }
                else if (dType == (long)XDataCode.AppReg)
                {
                    continue;
                }
                else if (dType == (long)XDataCode.ControlString)
                {
                    obj.Add(ret.AtString(i));
                }
                else if (dType == (long)XDataCode.LayerName)
                {
                    obj.Add(ret.AtString(i));
                }
                else if (dType == (long)XDataCode.BinaryData)
                {
                    obj.Add(ret.AtString(i));
                }
                else if (dType == (long)XDataCode.DatabaseHandle)
                {
                    obj.Add(ret.AtString(i));
                }
                else if (dType == (long)XDataCode.RealX)
                {
                    obj.Add(CadPointToJson(ret.AtPoint(i)));
                }
                else if (dType == (long)XDataCode.RealY)
                {

                }
                else if (dType == (long)XDataCode.RealZ)
                {

                }
                else if (dType == (long)XDataCode.WorldSpacePositionX)
                {
                    obj.Add(CadPointToJson(ret.AtPoint(i)));
                }
                else if (dType == (long)XDataCode.WorldSpacePositionY)
                {

                }
                else if (dType == (long)XDataCode.WorldSpacePositionZ)
                {

                }
                else if (dType == (long)XDataCode.WorldSpaceDisplacementX)
                {
                    obj.Add(CadPointToJson(ret.AtPoint(i)));

                }
                else if (dType == (long)XDataCode.WorldSpaceDisplacementY)
                {

                }
                else if (dType == (long)XDataCode.WorldSpaceDisplacementZ)
                {

                }
                else if (dType == (long)XDataCode.WorldDirectionX)
                {
                    obj.Add(CadPointToJson(ret.AtPoint(i)));

                }
                else if (dType == (long)XDataCode.WorldDirectionY)
                {

                }
                else if (dType == (long)XDataCode.WorldDirectionZ)
                {

                }
                else if (dType == (long)XDataCode.Real)
                {
                    obj.Add(ret.AtDouble(i));
                }
                else if (dType == (long)XDataCode.Distance)
                {
                    obj.Add(ret.AtDouble(i));
                }
                else if (dType == (long)XDataCode.ScaleFactor)
                {
                    obj.Add(ret.AtDouble(i));
                }
                else if (dType == (long)XDataCode.Int16)
                {
                    obj.Add(ret.AtLong(i));
                }
                else if (dType == (long)XDataCode.Int32)
                {
                    obj.Add(ret.AtLong(i));
                }
            }
            return obj;
        }

        public static JObject BuildCustomEntityParams(List<object> datas)
        {
            JObject obj = new JObject();
            int i = 0;
            string key = "";
            int code = -1;
            object value = null;
            foreach (var x in datas)
            {
                if (i % 3 == 0)
                {
                    key = (string)x;

                }
                else if (i % 3 == 1)
                {
                    code = (int)x;
                }
                else if (i % 3 == 2)
                {
                    value = x;
                    if (code == 5001)
                    {
                        // 浮点数
                        obj[key] = (double)value;
                    }
                    else if (code == 5005)
                    {
                        // 字符串
                        obj[key] = (string)value;
                    }
                    else if (code == 5010)
                    {
                        // 数字
                        obj[key] = (int)value;
                    }
                    else if (code == 5009)
                    {
                        //点坐标
                        obj[key] = JObject.FromObject(value);
                    }
                }
                i += 1;
            }
            return obj;
        }

        // 通过扩展数据提取自定义图元的几何参数
        // 注: 该方法得到的参数不完整, appname的个数和autocad中看到的不一致
        //     autocad中自定义图元以块引用的形式存在, 其xdata中包括多个appname，以Tunnel为例
        //             MXDRAW_CUSTOM_ENTITY_CLASSNAME、MXDRAW_CUSTOM_ENTITY_DATA、MXDRAW_CUSTOM_ENTITY_DATA1、MXDRAW_CUSTOM_ENTITY_DATA2
        //     但是，在ocx控件中xdata只有MXDRAW_CUSTOM_ENTITY_DATA1、MXDRAW_CUSTOM_ENTITY_DATA2这两个appname，其它的数据丢失了!
        public static JObject GetCustomEntityParamsByXData(MxDrawCustomEntity ent)
        {
            JObject obj = new JObject();
            string sType = ent.Guid;
            Console.WriteLine(sType);
            //if(sType == "Tunnel")
            //{
            //    Console.WriteLine(ent.IsHave("EndPoint"));
            //}
            // 如果通过cad打开ocx控件保存的dwg图形, 自定义图元是以块引用的形式存在
            // 图元内部使用的参数保存在xdata上, 包含如下几个appname, 每2个节点构成一对参数(key-value)
            // 比如：{1000-Tunnel} {1071-24}
            // 1000、1071是组码, 24表示数据类型是字符串"Tunnel"
            //JArray classname = GetEntityXData(ent, "MXDRAW_CUSTOM_ENTITY_CLASSNAME");
            //JArray xdata = GetEntityXData(ent, "MXDRAW_CUSTOM_ENTITY_DATA");
            //JArray xdata1 = GetEntityXData(ent, "MXDRAW_CUSTOM_ENTITY_DATA1");
            //JArray xdata2 = GetEntityXData(ent, "MXDRAW_CUSTOM_ENTITY_DATA2");

            MxDrawResbuf rb = ent.GetAllAppName();
            for (int i = 0; i < rb.Count; i++)
            {
                string appName = rb.AtString(i);
                Console.WriteLine(appName);
                List<object> xdata = GetEntityXData(ent, appName);
                int count = xdata.Count;
                Console.WriteLine(count);
                obj.Merge(BuildCustomEntityParams(xdata));
            }
            Console.WriteLine(obj.ToString());
            return obj;
        }

        // 从扩展词典里提取字段信息
        public static JObject GetFieldsFromExtDict(IMxDrawEntity ent, string dictKey)
        {
            MxDrawDictionary dict = GetExtDict(ent);
            MxDrawXRecord xRecord = (MxDrawXRecord)dict.GetAt(dictKey);
            if (xRecord == null) return null;

            MxDrawResbuf ret = xRecord.GetXRecordData();
            if (ret == null) return null;

            // 提取字段信息(json字符串)
            return JObject.Parse(ret.AtString(0));
        }

        // 通过扩展词典里的特殊key读取字段信息, 再提取参数
        public static JObject GetCustomEntityParamsByExtDict(MxDrawCustomEntity ent)
        {
            JObject fields = GetFieldsFromExtDict(ent, CUSTOM_ENTITY_FIELDS_DICT_KEY);
            JObject obj = new JObject();
            foreach (var item in fields)
            {
                string field = item.Key;
                int fieldType = item.Value.ToObject<int>();
                if (fieldType == (int)FieldType.STRING)
                {
                    obj[field] = ent.GetString(field);
                }
                else if (fieldType == (int)FieldType.INT)
                {
                    obj[field] = ent.GetLong(field);
                }
                else if (fieldType == (int)FieldType.FLOAT)
                {
                    obj[field] = ent.GetDouble(field);
                }
                else if (fieldType == (int)FieldType.BOOLEAN)
                {
                    obj[field] = ent.GetLong(field) != 0;
                }
                else if (fieldType == (int)FieldType.POINT)
                {
                    obj[field] = CadPointToJson(ent.GetPoint(field));
                }
                else if (fieldType == (int)FieldType.VECTOR)
                {
                    obj[field] = CadPointToJson(ent.GetPoint(field));
                }
                else if (fieldType == (int)FieldType.COLOR)
                {
                    obj[field] = ent.GetString(field);
                }
                else if (fieldType == (int)FieldType.LINETYPE)
                {
                    obj[field] = ent.GetString(field);
                }
                else if (fieldType == (int)FieldType.LINEWEIGHT)
                {
                    obj[field] = ent.GetLong(field);
                }
                else
                {
                    obj[field] = ent.GetString(field);
                }
            }
            return obj;
        }

        public static JObject GetEntityDatas(MxDrawEntity ent)
        {
            JObject obj = new JObject();
            MxDrawDictionary dict = GetExtDict(ent);
            JObject xdata = GET_DICT_XDATA(dict);
            foreach (var item in xdata)
            {
                JObject value = (JObject)item.Value;
                string key = value["field"].ToObject<String>();
                obj[key] = value["value"];
            }
            return obj;
        }

        public static JObject BuildEntityJsonData(MxDrawEntity ent)
        {
            JObject obj = new JObject();
            // 提取traits
            obj["layer"] = ent.Layer;
            obj["lineType"] = ent.LineType;
            obj["textStyle"] = ent.TextStyle;
            obj["colorIndex"] = (int)ent.colorIndex;
            obj["lineWeight"] = (int)ent.Lineweight;
            obj["trueColor"] = JsonConvert.SerializeObject(CadColorToJson(ent.TrueColor));
            //obj["handle"] = ent.handle;
            //obj["objectId"] = ent.ObjectID;
            obj["objectName"] = GetClassName(ent);


            // 提取params
            if (ent.ObjectName == "MxDrawXCustomEntity")
            {
                // 自定义图元从xdata中提取参数
                //obj["params"] = GetCustomEntityParamsByXData((MxDrawCustomEntity)ent);
                // 自定义图元从扩展词典中提取字段, 然后再利用MxDrawCustomEntity的api提取参数
                obj["params"] = GetCustomEntityParamsByExtDict((MxDrawCustomEntity)ent);
            }
            else
            {
                // 内置图元直接从object中提取参数
                JObject _params = GetEntityParams(ent);
                // 提取参数错误或者该图元因为某些规则被剔除掉
                if (_params == null) return null;

                HackGetEntityParams(ent, _params);
                obj["params"] = _params;
            }

            // 提取datas(从扩展词典中提取)
            obj["datas"] = GetEntityDatas(ent);
            return obj;
        }

        public static JObject BuildDatabaseJsonData(MxDrawDatabase database)
        {
            JObject obj = new JObject();
            //obj["objectName"] = database.ObjectName;
            obj["currentlyColorIndex"] = (int)database.CurrentlyColorIndex;
            obj["currentlyDimstyleName"] = database.CurrentlyDimstyleName;
            obj["currentlyLayerName"] = database.CurrentlyLayerName;
            obj["currentlyLineTypeName"] = database.CurrentlyLineTypeName;
            obj["currentlyLineTypeScale"] = database.CurrentlyLineTypeScale;
            obj["currentlyTextStyle"] = database.CurrentlyTextStyle;
            obj["currentlyTrueColor"] = JsonConvert.SerializeObject(CadColorToJson(database.CurrentlyTrueColor));
            obj["insbase"] = JsonConvert.SerializeObject(CadPointToJson(database.Insbase));
            obj["lineTypeScale"] = database.LinetypeScale;
            return obj;
        }

        public static string GetLineTypeNameById(MxDrawDatabase database, long id)
        {
            MxDrawMcDbObject obj = database.ObjectIdToObject(id);
            if (obj == null) return "";

            MxDrawLinetypeTableRecord linetypeTableRecord = (MxDrawLinetypeTableRecord)obj;
            if (linetypeTableRecord == null) return "";

            return linetypeTableRecord.Name;
        }

        public static JArray BuidlLayersJsonData(MxDrawDatabase database)
        {
            MxDrawLayerTable layerTable = database.GetLayerTable();
            MxDrawLayerTableIterator iter = layerTable.NewIterator();
            if (iter == null) return null;

            JArray datas = new JArray();

            // 遍历图层
            for (; !iter.Done(); iter.Step(true, true))
            {
                // layerTableRec代表一个图层
                var layerTableRec = iter.GetRecord();
                // 提取图层的参数
                JObject obj = new JObject();
                //obj["objectName"] = layerTableRec.ObjectName;
                //obj["handle"] = layerTableRec.handle;
                obj["name"] = layerTableRec.Name;
                obj["color"] = JsonConvert.SerializeObject(CadColorToJson(layerTableRec.Color));
                obj["isFrozen"] = layerTableRec.IsFrozen;
                obj["isLocked"] = layerTableRec.IsLocked;
                obj["isOff"] = layerTableRec.IsOff;
                obj["lineTypeName"] = GetLineTypeNameById(database, layerTableRec.LinetypeObjectId);
                obj["lineWeight"] = (int)layerTableRec.Lineweight;
                datas.Add(obj);
            }
            // 显式释放内存
            System.Runtime.InteropServices.Marshal.ReleaseComObject(iter);
            return datas;
        }

        public static JArray BuildLineTypesJsonData(MxDrawDatabase database)
        {
            MxDrawLinetypeTable lineTypeTable = database.GetLinetypeTable();
            MxDrawLinetypeTableIterator iter = lineTypeTable.NewIterator();
            if (iter == null) return null;

            JArray datas = new JArray();
            for (; !iter.Done(); iter.Step(true, true))
            {
                MxDrawLinetypeTableRecord lineTypeTableRec = iter.GetRecord();
                JObject obj = new JObject();
                //obj["objectName"] = lineTypeTableRec.ObjectName;
                //obj["handle"] = lineTypeTableRec.handle;
                obj["name"] = lineTypeTableRec.Name;
                obj["comments"] = lineTypeTableRec.Comments;
                obj["numDashes"] = lineTypeTableRec.NumDashes;
                // 人为添加: 线型定义数据
                double[] dashes = new double[lineTypeTableRec.NumDashes];
                for (int i = 0; i < lineTypeTableRec.NumDashes; i++)
                {
                    dashes[i] = lineTypeTableRec.DashLengthAt(i);
                }
                // obj["dashes"] = string.Join(, dashes);
                obj["dashes"] = JsonConvert.SerializeObject(dashes);
                datas.Add(obj);
            }
            System.Runtime.InteropServices.Marshal.ReleaseComObject(iter);
            return datas;
        }

        public static JArray BuildTextStylesJsonData(MxDrawDatabase database)
        {
            var textStyleTable = database.GetTextStyleTable();
            var iter = textStyleTable.NewIterator();
            if (iter == null) return null;

            JArray datas = new JArray();
            for (; !iter.Done(); iter.Step(true, true))
            {
                var textStyleTableRec = iter.GetRecord();
                JObject obj = new JObject();
                //obj["objectName"] = textStyleTableRec.ObjectName;
                //obj["handle"] = textStyleTableRec.handle;
                obj["name"] = textStyleTableRec.Name;
                obj["bigFontFileName"] = textStyleTableRec.bigFontFileName;
                obj["fileName"] = textStyleTableRec.fileName;
                obj["isShapeFile"] = textStyleTableRec.isShapeFile;
                obj["isVertical"] = textStyleTableRec.isVertical;
                obj["obliquingAngle"] = textStyleTableRec.obliquingAngle;
                obj["textSize"] = textStyleTableRec.textSize;

                // // 得到TrueType字体属性
                var typeface = "宋体";
                var bold = false;
                var italic = false;
                var charset = 134;
                var pitchAndFamily = 2;
                textStyleTableRec.Font(out typeface, out bold, out italic, out charset, out pitchAndFamily);
                obj["typeface"] = typeface;
                obj["bold"] = bold;
                obj["italic"] = italic;
                obj["charset"] = charset;
                obj["pitchAndFamily"] = pitchAndFamily;

                datas.Add(obj);
            }
            // 显式释放内存
            System.Runtime.InteropServices.Marshal.ReleaseComObject(iter);
            return datas;
        }

        public static JArray BuildDimStylesJsonData(MxDrawDatabase database)
        {
            // 读取标注变量json配置文件
            JObject DimStyleVariables = JObject.Parse(File.ReadAllText("DimVars.json"));

            var dimStyleTable = database.GetDimStyleTable();
            var iter = dimStyleTable.NewIterator();
            if (iter == null) return null;

            JArray datas = new JArray();
            for (; !iter.Done(); iter.Step(true, true))
            {
                var dimStyleTableRec = iter.GetRecord();
                JObject obj = new JObject();
                //obj["objectName"] = dimStyleTableRec.ObjectName;
                //obj["handle"] = dimStyleTableRec.handle;
                obj["name"] = dimStyleTableRec.Name;

                JObject vars = new JObject();
                foreach (var item in DimStyleVariables)
                {
                    string name = item.Key;
                    JObject _var = (JObject)item.Value;
                    var code = _var["code"].ToObject<int>();
                    var type = _var["type"].ToObject<string>();
                    var value = _var["value"];
                    try
                    {
                        if (type == "int")
                        {
                            vars[name] = dimStyleTableRec.GetDimVarInt(code);
                        }
                        else if (type == "double")
                        {
                            vars[name] = dimStyleTableRec.GetDimVarDouble(code);
                        }
                        else if (type == "string")
                        {
                            vars[name] = dimStyleTableRec.GetDimVarString(code);
                        }
                        else
                        {
                            vars[name] = value;
                        }
                    }
                    catch (Exception)
                    {
                        vars[name] = value;
                    }
                }
                // 人为添加: vars, 记录标注样式的所有数据
                obj["vars"] = vars;

                datas.Add(obj);
            }
            // 显式释放内存
            System.Runtime.InteropServices.Marshal.ReleaseComObject(iter);
            return datas;
        }

        public static JArray GET_XRECORD_VALUES(MxDrawResbuf resbuf)
        {
            if (resbuf != null)
            {
                JArray datas = new JArray();

                // 汇总当前词典下的所有key
                for (var i = 0; i < resbuf.Count; i++)
                {
                    // 按照 string->double->int->point的顺序, 依次猜测数据值
                    // resbuf.ItemDataType(i);
                    bool ret = false;
                    if (!ret)
                    {
                        try
                        {
                            datas.Add(resbuf.AtString(i));
                            ret = true;
                        }
                        catch (Exception)
                        {
                            ret = false;
                        }
                    }

                    if (!ret)
                    {
                        try
                        {
                            datas.Add(resbuf.AtDouble(i));
                            ret = true;
                        }
                        catch (Exception)
                        {
                            ret = false;
                        }
                    }

                    if (!ret)
                    {
                        try
                        {
                            datas.Add(resbuf.AtLong(i));
                            ret = true;
                        }
                        catch (Exception)
                        {
                            ret = false;
                        }
                    }

                    if (!ret)
                    {
                        try
                        {
                            datas.Add(CadPointToJson(resbuf.AtPoint(i)));
                            ret = true;
                        }
                        catch (Exception)
                        {
                            ret = false;
                        }
                    }
                }
                return datas;
            }
            else
            {
                return null;
            }
        }

        // 词典辅助工具类
        public static JObject GetAllDictionaryDataCall(MxDrawDictionary dict)
        {
            // 创建一个字典遍历器
            var iter = dict.NewIterator();
            JObject datas = new JObject();
            for (; !iter.Done(); iter.Step())
            {
                // 遍历到每个字典，取出名称.
                var sName = iter.Name();
                var obj = iter.GetObject();
                if (obj == null) continue;
                Console.WriteLine("尝试读取扩展记录:{0} {1}", sName, obj.ObjectName);

                // TODO 目前键值仅支持词典 和 扩展记录 两种内置类型, 不支持自定义对象
                // 扩展记录仅支持字符串、浮点数、整数、坐标点类型
                if (obj.ObjectName == "McDbDictionary")
                {
                    var tmpDict = (MxDrawDictionary)obj;
                    datas[sName] = GetAllDictionaryDataCall(tmpDict);
                }
                else if (obj.ObjectName == "McDbXrecord")
                {
                    var tmpXRecord = (MxDrawXRecord)obj;
                    // 尝试提取扩展记录里的数据
                    var xRecord = tmpXRecord.GetXRecordData();
                    if (xRecord == null) continue;

                    var values = GET_XRECORD_VALUES(xRecord);
                    if (values == null) continue;

                    if (values.Count == 0)
                    {
                        datas[sName] = "";
                    }
                    else if (values.Count == 1)
                    {
                        // 如果只有1个数据, 将数组转换为单个数据
                        datas[sName] = values[0];
                    }
                    else
                    {
                        // 转换为json字符串
                        datas[sName] = JsonConvert.SerializeObject(values);
                    }
                }
            }
            System.Runtime.InteropServices.Marshal.ReleaseComObject(iter);
            return datas;
        }

        public static JArray BuildDictsJsonData(MxDrawDatabase database)
        {
            var nodDict = database.GetNamedObjectsDictionary();

            JArray datas = new JArray();
            // 创建一个字典遍历器
            var iter = nodDict.NewIterator();
            for (; !iter.Done(); iter.Step())
            {
                // 遍历到每个字典，取出名称.
                var sName = iter.Name();
                // 忽略内置的一些字典: 以ACAD_开头
                if (sName.ToUpper() == "ACDBVARIABLEDICTIONARY" || sName.StartsWith("ACAD_"))
                {
                    continue;
                }

                MxDrawDictionary childDict = (MxDrawDictionary)iter.GetObject();
                if (childDict == null) continue;

                Console.WriteLine("读取自定义词典:{0}", sName);

                JObject obj = new JObject();
                //obj["objectName"] = childDict.ObjectName;
                //obj["handle"] = childDict.handle;
                // 人为添加数据
                obj["name"] = sName;
                obj["key_values"] = GetAllDictionaryDataCall(childDict);
                datas.Add(obj);
            }
            System.Runtime.InteropServices.Marshal.ReleaseComObject(iter);
            return datas;
        }

        // 例如: objectNames = ["McDbLine", "Joint", "Tunnel", "McDbArc"....]
        public static JArray GetEntityDatasInBlockByType(MxDrawBlockTableRecord blockTableRec, string[] objectNames)
        {
            HashSet<string> objectNameSet = new HashSet<string>(objectNames);

            MxDrawBlockTableRecordIterator iter = blockTableRec.NewIterator();
            JArray entities = new JArray();
            for (; !iter.Done(); iter.Step(true, true))
            {
                // 得到遍历器当前的实体
                MxDrawEntity ent = iter.GetEntity();
                // 记录id
                //objIds.Add(ent.ObjectID);
                JObject obj = null;
                if (objectNameSet.Contains(ent.ObjectName))
                {
                    obj = BuildEntityJsonData(ent);
                }
                else if (ent.ObjectName == "MxDrawXCustomEntity")
                {
                    string sType = ((MxDrawCustomEntity)ent).Guid;
                    if (objectNameSet.Contains(sType))
                    {
                        obj = BuildEntityJsonData(ent);
                    }
                }
                if (obj != null)
                {
                    entities.Add(obj);
                }
            }
            return entities;
        }

        public static JArray GetEntityDatasInBlock(MxDrawBlockTableRecord blockTableRec, EntityType entityType)
        {
            MxDrawBlockTableRecordIterator iter = blockTableRec.NewIterator();
            JArray entities = new JArray();
            for (; !iter.Done(); iter.Step(true, true))
            {
                JObject obj = null;
                // 得到遍历器当前的实体
                MxDrawEntity ent = iter.GetEntity();
                if (ent.ObjectName == "McDbPoint")
                {
                    // 忽略点图元(不可见, 还会导致图形缩放比例不正确)
                    continue;
                }
                // 记录id
                //objIds.Add(ent.ObjectID);
                if (entityType == EntityType.BUILTIN && ent.ObjectName != "MxDrawXCustomEntity")
                {
                    // 自定义图元
                    obj = BuildEntityJsonData(ent);
                }
                else if (entityType == EntityType.CUSTOM && ent.ObjectName == "MxDrawXCustomEntity")
                {
                    // 内置图元
                    obj = BuildEntityJsonData(ent);
                }
                else if (entityType == EntityType.ALL)
                {
                    // 所有图元
                    obj = BuildEntityJsonData(ent);
                }

                if (obj != null)
                {
                    entities.Add(obj);
                }
            }
            System.Runtime.InteropServices.Marshal.ReleaseComObject(iter);
            return entities;
        }

        public static JArray SplitEntitiesToChunk(JArray entities, int chunkSize, bool enableGzipCompression)
        {
            JArray datas = new JArray();
            if (entities == null || entities.Count == 0) return datas;

            int start = 0;
            int totoalCount = entities.Count;

            while (start < totoalCount)
            {
                int end = start + chunkSize;
                if (end > totoalCount)
                {
                    end = totoalCount;
                }
                JArray chunkEntities = new JArray();
                for (int i = start; i < end; i++)
                {
                    chunkEntities.Add(entities[i]);
                }
                if (enableGzipCompression)
                {
                    // 分块压缩成字符串
                    datas.Add(CompressObject(chunkEntities));
                }
                else
                {
                    // 分块不压缩
                    datas.Add(chunkEntities);
                }
                start = end;
            }
            return datas;
        }

        public static JArray BuildBlocksJsonData(MxDrawDatabase database, bool enableGzipCompression)
        {
            var blockTable = database.GetBlockTable();
            var iter = blockTable.NewIterator();
            if (iter == null) return null;

            JArray datas = new JArray();
            for (; !iter.Done(); iter.Step(true, true))
            {
                var blockTableRec = iter.GetRecord();
                // 跳过模型空间
                if (blockTableRec.Name == "*Model_Space" || blockTableRec.Name == "*Paper_Space" || blockTableRec.Name == "*Paper_Space0") continue;

                // 空的块定义
                JArray entities = GetEntityDatasInBlock(blockTableRec, EntityType.ALL);
                if (entities == null || entities.Count == 0)
                {
                    // 记录空的块定义
                    EMPTY_BLOCK_HASH_SET.Add(blockTableRec.Name);
                    continue;
                }

                // 提取块定义中的基础数据
                JObject obj = new JObject();
                //obj["objectName"] = blockTableRec.ObjectName;
                //obj["handle"] = blockTableRec.handle;
                obj["name"] = blockTableRec.Name;
                obj["origin"] = JsonConvert.SerializeObject(CadPointToJson(blockTableRec.Origin));

                // (块定义里的图元数量很少,最多几十几百个, 不需要分块
                if (enableGzipCompression)
                {
                    // 压缩成字符串
                    obj["entities"] = CompressObject(entities);
                }
                else
                {
                    // 不压缩
                    obj["entities"] = entities;
                }
                datas.Add(obj);
            }
            // 显式释放内存
            System.Runtime.InteropServices.Marshal.ReleaseComObject(iter);
            return datas;
        }

        public static string CompressObject(object value)
        {
            return ZipUtil.GZipCompressString(JsonConvert.SerializeObject(value));
        }

        public static JObject MakeJsonResult(int code, object data, string msg)
        {
            return new JObject()
            {
                new JProperty("code", code),
                new JProperty("data", data),
                new JProperty("msg", msg),
            };
        }
        //public static JObject MakeJsonResult(int code, JObject data, string msg)
        //{
        //    return new JObject()
        //    {
        //        {"code", code },
        //        {"data", data },
        //        {"msg", msg }
        //    };
        //}

        public class Options
        {

            [Option("json", Required = true, HelpText = "output json file")]
            public string JsonFile { get; set; }

            [Option("dwg", Required = true, HelpText = "input dwg file")]
            public string DwgFile { get; set; }

            [Option("chunk", Required = false, Default = 10000, HelpText = "entity chunk size")]
            public int ChunkSize { get; set; }

            [Option("zip", Required = false, Default = false, HelpText = "disable gzip compress")]
            public bool EnableGzipCompression { get; set; }

            [Option("without-database", Required = false, Default = false, HelpText = "disable parse database")]
            public bool WithoutDatabase { get; set; }

            [Option("without-layer", Required = false, Default = false, HelpText = "disable parse layers")]
            public bool WithoutLayer { get; set; }

            [Option("without-linetype", Required = false, Default = false, HelpText = "disable parse linetypes")]
            public bool WithoutLineType { get; set; }

            [Option("without-textstyle", Required = false, Default = false, HelpText = "disable parse text styles")]
            public bool WithoutTextStyle { get; set; }

            [Option("without-dimstyle", Required = false, Default = false, HelpText = "disable parse dim styles")]
            public bool WithoutDimStyle { get; set; }

            [Option("without-dict", Required = false, Default = false, HelpText = "disable parse custom dict")]
            public bool WithoutDict { get; set; }

            [Option("without-block", Required = false, Default = false, HelpText = "disable parse block definition")]
            public bool WithoutBlock { get; set; }

            [Option("without-builtin-entity", Required = false, Default = false, HelpText = "disable parse builtin entities")]
            public bool WithoutBuiltinEntity { get; set; }

            [Option("without-custom-entity", Required = false, Default = false, HelpText = "disable parse custom entities")]
            public bool WithoutCustomEntity { get; set; }
        }


        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        public static void Main(string[] args)
        {
            try
            {
                // 删除残留的文件
                File.Delete(ERROR_FILE);
                string dwgFile = "";
                string jsonFile = "";
                bool withoutDatabase = false;
                bool withoutLayer = false;
                bool withoutLineType = false;
                bool withoutTextStyle = false;
                bool withoutDimStyle = false;
                bool withoutDict = false;
                bool withoutBlock = false;
                bool withoutBuiltinEntity = false;
                bool withoutCustomEntity = false;
                Parser.Default.ParseArguments<Options>(args)
                  .WithParsed<Options>(options =>
                  {
                      // 使用解析后的命令行参数进行操作。
                      dwgFile = options.DwgFile;
                      jsonFile = options.JsonFile;
                      if (options.ChunkSize > 0)
                      {
                          ENTITY_CHUNK_SIZE = options.ChunkSize;
                      }
                      if (options.EnableGzipCompression)
                      {
                          ENABLE_GZIP_COMPRESSION = true;
                      }
                      if (options.WithoutDatabase)
                      {
                          withoutDatabase = true;
                      }
                      if (options.WithoutLayer)
                      {
                          withoutLayer = true;
                      }
                      if (options.WithoutLineType)
                      {
                          withoutLineType = true;
                      }
                      if (options.WithoutTextStyle)
                      {
                          withoutTextStyle = true;
                      }
                      if (options.WithoutDimStyle)
                      {
                          withoutDimStyle = true;
                      }
                      if (options.WithoutDict)
                      {
                          withoutDict = true;
                      }
                      if (options.WithoutBlock)
                      {
                          withoutBlock = true;
                      }
                      if (options.WithoutBuiltinEntity)
                      {
                          withoutBuiltinEntity = true;
                      }
                      if (options.WithoutCustomEntity)
                      {
                          withoutCustomEntity = true;
                      }
                  });

                // 创建一个无控件界面的服务器组件对象
                MxDrawService ser = new MxDrawService();

                // 打开dwg文件
                if (!ser.Open(dwgFile))
                {
                    throw new Exception(string.Format("打开文件{0}失败", dwgFile));
                }

                // 得到打开文件的数据库
                MxDrawDatabase database = ser.GetDatabase();

                JObject data = new JObject()
            {
                    new JProperty("database", withoutDatabase ? null : BuildDatabaseJsonData(database)),
                    new JProperty("layers", withoutLayer ? null : BuidlLayersJsonData(database)),
                    new JProperty("lineTypes",withoutLineType ? null : BuildLineTypesJsonData(database)),
                    new JProperty("textStyles", withoutTextStyle ? null : BuildTextStylesJsonData(database)),
                    new JProperty("dimStyles", withoutDimStyle ? null : BuildDimStylesJsonData(database)),
                    new JProperty("dicts", withoutDict ? null : BuildDictsJsonData(database)),
                    new JProperty("blocks", withoutBlock ? null : BuildBlocksJsonData(database, ENABLE_GZIP_COMPRESSION)),
                    new JProperty("builtinEntities", withoutBuiltinEntity ? null : SplitEntitiesToChunk(GetEntityDatasInBlock(database.CurrentSpace(), EntityType.BUILTIN), ENTITY_CHUNK_SIZE, ENABLE_GZIP_COMPRESSION)),
                    new JProperty("customEntities", withoutCustomEntity ? null : SplitEntitiesToChunk(GetEntityDatasInBlock(database.CurrentSpace(), EntityType.CUSTOM), ENTITY_CHUNK_SIZE, ENABLE_GZIP_COMPRESSION))
            };
                // 关闭service对象
                ser.Close();
                //Console.WriteLine(obj.ToString());
                // 返回格式: {code, msg, data}
                //File.WriteAllText(jsonFile, JsonConvert.SerializeObject(MakeJsonResult(0, data, "")));
                File.WriteAllText(jsonFile, JsonConvert.SerializeObject(data));
            }
            catch (Exception e)
            {
                File.WriteAllText(ERROR_FILE, e.Message);
                //File.WriteAllText(jsonFile, JsonConvert.SerializeObject(MakeJsonResult(1, null, e.Message)));
            }

        }
    }
}